package environment.dungeons;

import static org.junit.Assert.*;

import org.junit.*;

import environment.Direction;
import environment.Position;
import environment.borders.Border;
import environment.borders.Door;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import temperature.Temperature;
import temperature.TemperatureUnit;

/**
 * Een testklasse voor de klasse Square.
 * Deze bevat de testmethoden voor het testen van de toegankelijkheid van 2 vakjes.
 * 
 * @author 	Nathan Bekaert & Philippe de Potter de ten Broeck
 * @version 1.0
 */
public class SquareTest {

	private Square square1;
	private Square square2;
	private static CompositeDungeon<Square> compDungeon1;
	private static CompositeDungeon<Square> compDungeon2;
	private static CompositeDungeon<Square> compDungeon3;
	private static Dungeon<Square> level1;
	private static Dungeon<NormalSquare> level2;
	private static Dungeon<TransparentSquare> level3;
	private static Dungeon<TeleportableSquare> shaft1;
	private static Dungeon<TeleportableSquare> shaft2;
	private static Dungeon<NormalSquare> shaft3;
	private static Dungeon<TransparentSquare> shaft4;
	private static Set<Square> room1 = new HashSet<Square>();
	private static Set<Square> room2 = new HashSet<Square>();
	private static Set<Square> room3 = new HashSet<Square>();
	private static Set<Square> room4 = new HashSet<Square>();
	private static Set<Square> room5 = new HashSet<Square>();
	private static Set<Square> room6 = new HashSet<Square>();
	private static Set<Square> room7 = new HashSet<Square>();
	private static Set<Square> room8 = new HashSet<Square>();
	private static Set<Square> dungeon1rooms = new HashSet<Square>();
	private static Set<Square> dungeon2rooms = new HashSet<Square>();
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		// Construction of dungeons
		compDungeon1 = new CompositeDungeon<Square>(50, 50, 0);
		compDungeon2 = new CompositeDungeon<Square>(50, 50, 0);
		compDungeon3 = new CompositeDungeon<Square>(50, 50, 0);
		level1 = new Level<Square>(25, 25);
		level2 = new Level<NormalSquare>(24, 24);
		level3 = new Level<TransparentSquare>(25, 25);
		shaft1 = new Shaft<TeleportableSquare>(24, Direction.NORTH);
		shaft2 = new Shaft<TeleportableSquare>(24, Direction.NORTH);
		shaft3 = new Shaft<NormalSquare>(24, Direction.WEST);
		shaft4 = new Shaft<TransparentSquare>(50, Direction.NORTH);
		
		//Fill compositedungeons with subDungeons
		compDungeon1.addSubDungeonAt(level1, 0, 0, 0);
		compDungeon1.addSubDungeonAt(level2, 26, 26, 0);
		compDungeon1.addSubDungeonAt(shaft1, 0, 26, 0);
		compDungeon1.addSubDungeonAt(shaft2, 5, 26, 0);
		compDungeon1.addSubDungeonAt(shaft3, 26, 0, 0);
		compDungeon2.addSubDungeonAt(level3, 0, 0, 0);
		compDungeon3.addSubDungeonAt(shaft4, 0, 0, 0);
		
		//Fill levels with squares
			//Level1
		for(int x = 20; x <= 25; x++)
			for(int y = 20; y <= 25; y++) {
				Position pos = new Position(x, y, 0);
				level1.addSquareAt(new NormalSquare(), pos);
				room2.add(level1.getSquareAt(pos));
			}
		for(int x = 1; x <= 4; x++)
			for(int y = 1; y <= 25; y++) {
				Position pos = new Position(x, y, 0);
				level1.addSquareAt(new Rock(), pos);
			}
		level1.removeSquareAt(new Position(1, 1, 0));
		level1.addSquareAt(new NormalSquare(), new Position(1, 1, 0));
		room1.add(level1.getSquareAt(new Position(1, 1, 0)));
		for(int x = 1; x <= 25; x++) {
			Position pos = new Position(x, 0, 0);
			level1.addSquareAt(new NormalSquare(), pos);
			room1.add(level1.getSquareAt(pos));
		}
		for(int y = 1; y <= 25; y++) {
			Position pos = new Position(0, y, 0);
			level1.addSquareAt(new NormalSquare(), pos);
			room1.add(level1.getSquareAt(pos));
		}
		for(int y = 1; y <= 25; y++) {
			Position pos = new Position(5, y, 0);
			level1.addSquareAt(new NormalSquare(), pos);
			room1.add(level1.getSquareAt(pos));
		}
			//Level2
		for(int x = 0; x <= 5; x++)
			for(int y = 0; y <= 5; y++) {
				Position pos = new Position(x, y, 0);
				level2.addSquareAt(new NormalSquare(), pos);
				room5.add(level2.getSquareAt(pos));
			}
			//Level3
		for(int y = 1; y <= 10; y++) {
			Position pos = new Position(0, y, 0);
			level3.addSquareAt(new TransparentSquare(Direction.FLOOR), pos);
			room6.add(level3.getSquareAt(pos));
		}
		for(int y = 0; y <= 10; y++) {
			Position pos = new Position(19, y, 0);
			level3.addSquareAt(new TransparentSquare(Direction.FLOOR), pos);
			room6.add(level3.getSquareAt(pos));
		}
		for(int x = 1; x <= 18; x++) {
			Position pos = new Position(x, 10, 0);
			level3.addSquareAt(new TransparentSquare(Direction.FLOOR), pos);
			room6.add(level3.getSquareAt(pos));
		}
		for(int x = 20; x <= 25; x++)
			for(int y = 20; y <= 25; y++) {
				Position pos = new Position(x, y, 0);
				level3.addSquareAt(new TransparentSquare(Direction.FLOOR), pos);
				room7.add(level3.getSquareAt(pos));
			}
		
		//Fill shafts with squares
			//Shaft1
		compDungeon1.addSquareAt(new NormalSquare(Temperature.CELSIUS_0, BigDecimal.TEN, Direction.SOUTH), new Position(0, 26, 0));
		room3.add(compDungeon1.getSquareAt(new Position(0, 26, 0)));
		for(int y = 27; y <= 30; y++) {
			Position pos = new Position(0, y, 0);
			compDungeon1.addSquareAt(new NormalSquare(), pos);
			room3.add(compDungeon1.getSquareAt(pos));
		}
			//Shaft2
		Square square = new NormalSquare();
		square.buildNewBorderIn(new Door(false), Direction.SOUTH);
		compDungeon1.addSquareAt(square, new Position(5, 26, 0));
		room4.add(compDungeon1.getSquareAt(new Position(5, 26, 0)));
		for(int y = 27; y <= 30; y++) {
			Position pos = new Position(5, y, 0);
			compDungeon1.addSquareAt(new NormalSquare(), pos);
			room4.add(compDungeon1.getSquareAt(pos));
		}
			//Shaft3
		Square sq = new NormalSquare();
		sq.buildNewBorderIn(new Door(true), Direction.WEST);
		compDungeon1.addSquareAt(sq, new Position(26, 0, 0));
		room1.add(compDungeon1.getSquareAt(new Position(26, 0, 0)));
		for(int x = 27; x <= 30; x++) {
			Position pos = new Position(x, 0, 0);
			compDungeon1.addSquareAt(new NormalSquare(), pos);
			room1.add(compDungeon1.getSquareAt(pos));
		}
			//Shaft4
		for(int y = 1; y <= 10; y++) {
			Position pos = new Position(0, y, 0);
			shaft4.addSquareAt(new TransparentSquare(Direction.WEST), pos);
			room8.add(shaft4.getSquareAt(pos));
		}
		
		//Add rooms in dungeons 1 & 2 to new set
		dungeon1rooms.addAll(room1);
		dungeon1rooms.addAll(room2);
		dungeon1rooms.addAll(room3);
		dungeon1rooms.addAll(room4);
		dungeon1rooms.addAll(room5);
		dungeon2rooms.addAll(room6);
		dungeon2rooms.addAll(room7);
		
		//Set teleportability
		TeleportableSquare tele;
		TeleportableSquare destination;
		
		tele = (TeleportableSquare) level1.getSquareAt(new Position(0, 25, 0));
		tele.setTeleportable(true);
		destination = level3.getSquareAt(new Position(25, 25, 0));
		tele.addAsTeleportationSquare(destination);
		destination = (TeleportableSquare) level1.getSquareAt(new Position(25, 25, 0));
		tele.addAsTeleportationSquare(destination);
		
		tele = (TeleportableSquare) shaft1.getSquareAt(new Position(0, 2, 0));
		tele.setTeleportable(true);
		destination = shaft4.getSquareAt(new Position(0, 10, 0));
		tele.addAsTeleportationSquare(destination);
		
		tele = (TeleportableSquare) shaft2.getSquareAt(new Position(0, 2, 0));
		tele.setTeleportable(true);
		destination = shaft1.getSquareAt(new Position(0, 0, 0));
		tele.addAsTeleportationSquare(destination);
		
		tele = (TeleportableSquare) shaft2.getSquareAt(new Position(0, 0, 0));
		tele.setTeleportable(true);
		destination = level2.getSquareAt(new Position(0, 0, 0));
		tele.addAsTeleportationSquare(destination);
		
		tele = (TeleportableSquare) shaft3.getSquareAt(new Position(2, 0, 0));
		tele.setTeleportable(true);
		destination = shaft2.getSquareAt(new Position(0, 2, 0));
		tele.addAsTeleportationSquare(destination);
		
		tele = (TeleportableSquare) shaft4.getSquareAt(new Position(0, 1, 0));
		tele.setTeleportable(true);
		destination = level3.getSquareAt(new Position(25, 25, 0));
		tele.addAsTeleportationSquare(destination);
		
		tele = (TeleportableSquare) level3.getSquareAt(new Position(19, 0, 0));
		tele.setTeleportable(true);
		destination = level3.getSquareAt(new Position(25, 25, 0));
		tele.addAsTeleportationSquare(destination);
		
		tele = (TeleportableSquare) level3.getSquareAt(new Position(25, 25, 0));
		tele.setTeleportable(true);
		destination = level3.getSquareAt(new Position(19, 0, 0));
		tele.addAsTeleportationSquare(destination);
	}
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}
	@Before
	public void setUp() throws Exception {
		square1 = new NormalSquare();
		square2 = new NormalSquare(Temperature.CELSIUS_0,new BigDecimal(50.00));
	}
	@After
	public void tearDown() throws Exception {
	}
	
	
	//TEMPERATUUR (Defensief)
	@Test
	public void testTemperatureLimits(){
		assertEquals(square1.getLowerLimitTemperature().getTemperatureValueIn(TemperatureUnit.CELSIUS).compareTo(new BigDecimal(-200)),0);
		assertEquals(square1.getUpperLimitTemperature().getTemperatureValueIn(TemperatureUnit.CELSIUS).compareTo(new BigDecimal(5000)),0);
	}
	@Test
	public void testChangedTemperatureLimits() throws Exception{
		square1.setLimitsTemperature(new Temperature(BigDecimal.ZERO,TemperatureUnit.CELSIUS), 
				new Temperature(new BigDecimal(200),TemperatureUnit.CELSIUS));
		assertEquals(square1.getLowerLimitTemperature().getTemperatureValueIn(TemperatureUnit.CELSIUS).compareTo(new BigDecimal(0)),0);
		assertEquals(square1.getUpperLimitTemperature().getTemperatureValueIn(TemperatureUnit.CELSIUS).compareTo(new BigDecimal(200)),0);
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureLimitsNotMatching() throws Exception{
		square1.setLimitsTemperature(new Temperature(new BigDecimal(500),TemperatureUnit.CELSIUS), 
				new Temperature(new BigDecimal(100),TemperatureUnit.CELSIUS));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureLimitsNullUnderLimit() throws Exception{
		square1.setLimitsTemperature(null, 
				new Temperature(new BigDecimal(100),TemperatureUnit.CELSIUS));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureLimitsNullUpperLimit() throws Exception{
		square1.setLimitsTemperature(new Temperature(new BigDecimal(500),TemperatureUnit.CELSIUS)
				,null);
	}
	@Test
	public void testTemperature(){
		assertEquals(square1.getTemperature().getTemperatureValueIn(TemperatureUnit.CELSIUS).compareTo(BigDecimal.ZERO),0);
	}
	@Test 
	public void testChangedTemperatureConvertToLimit() throws IllegalArgumentException, IllegalStateException{
		square1.alterTemperature(new Temperature(new BigDecimal(5273), TemperatureUnit.KELVIN));
		assertEquals(square1.getTemperature().getTemperatureValueIn(TemperatureUnit.KELVIN).compareTo(new BigDecimal(5273)),0);
	}
	@Test
	public void testChangedTemperature() throws IllegalArgumentException, IllegalStateException{
		square1.alterTemperature(new Temperature(BigDecimal.ONE, TemperatureUnit.FAHRENHEIT));
		assertEquals(square1.getTemperature().getTemperatureValueIn(TemperatureUnit.FAHRENHEIT).compareTo(BigDecimal.ONE),0);
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureTooLow() throws IllegalArgumentException, IllegalStateException{
		square1.alterTemperature(new Temperature(BigDecimal.ONE, TemperatureUnit.KELVIN));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureTooHigh() throws IllegalArgumentException, IllegalStateException{
		square1.alterTemperature(new Temperature(new BigDecimal(9400), TemperatureUnit.FAHRENHEIT));
	}
	@Test(expected=IllegalArgumentException.class)
	public void testChangedTemperatureFalseConversion() throws IllegalArgumentException, IllegalStateException{
		square1.alterTemperature(new Temperature(new BigDecimal(30), TemperatureUnit.KELVIN));
	}
	
	//SCHADE door temp (defensief)
	
	@Test
	public void testColdDamage()throws Exception{
		square1.alterTemperature(new Temperature(new BigDecimal(20), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(-5), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(-14), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(-15), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 1);
		square1.alterTemperature(new Temperature(new BigDecimal(-16), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 1);
		square1.alterTemperature(new Temperature(new BigDecimal(-91), TemperatureUnit.CELSIUS));
		assertEquals(square1.coldDamage(), 8);
	}
	@Test
	public void testHeatDamage()throws Exception{
		square1.alterTemperature(new Temperature(new BigDecimal(20), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(35), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(49), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(50), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.alterTemperature(new Temperature(new BigDecimal(51), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.alterTemperature(new Temperature(new BigDecimal(118), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 5);
	}
	@Test (expected=ArithmeticException.class)
	public void testHeatDamageOutOfUpperBound() throws Exception{
		square1.setLimitsTemperature(square1.getLowerLimitTemperature(),
				new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.alterTemperature(square1.getUpperLimitTemperature());
		square1.heatDamage();
	}
	@Test
	public void testHeatDamageChanged()throws Exception{
		square1.setHeatDamageSlope(new BigDecimal(20));
		square1.setHeatDamageBorder(new Temperature(new BigDecimal(50), TemperatureUnit.CELSIUS));
		square1.alterTemperature(new Temperature(new BigDecimal(30), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(50), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(69), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 0);
		square1.alterTemperature(new Temperature(new BigDecimal(70), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.alterTemperature(new Temperature(new BigDecimal(71), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 1);
		square1.alterTemperature(new Temperature(new BigDecimal(181), TemperatureUnit.CELSIUS));
		assertEquals(square1.heatDamage(), 6);
	}
	
	
	//Vochtigheid en roest(nominaal)
	
	@Test 
	public void testHumidity(){
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(1000),2))==0);
	}
	@Test 
	public void testHumidityChanged(){
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(8000),2));
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(8000),2))==0);
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(1000),1))==0);
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(0000),2));
		assertTrue(square1.getHumidity().compareTo(new BigDecimal(BigInteger.valueOf(000),2))==0);
	}
	@Test 
	public void testHumidityPres(){
		assertFalse(Square.isValidHumidity(new BigDecimal(BigInteger.valueOf(-5000),2)));
		assertFalse(Square.isValidHumidity(new BigDecimal(BigInteger.valueOf(20000),2)));
	}
	@Test
	public void testRustDamage(){
		assertEquals(square1.rustDamage(),0);
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		assertEquals(square1.rustDamage(),10);
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(3700),2));
		assertEquals(square1.rustDamage(),1);
	}

	
	//Gladheid (defensief):

	@Test 
	public void testSlippery(){
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
	}
	@Test 
	public void testSlipperyWater() throws IllegalArgumentException, IllegalStateException{
		square1.alterTemperature(Temperature.CELSIUS_1);
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(9900),2));
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		assertTrue(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertTrue(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
	}
	@Test 
	public void testSlipperyIce() throws IllegalArgumentException, IllegalStateException{
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(2000),2));
		assertTrue(square1.isSlippery());
		assertTrue(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.alterTemperature(Temperature.CELSIUS_1);
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(5000),2));
		assertFalse(square1.isSlippery());
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
		square1.alterTemperature(Temperature.CELSIUS_0);
		assertTrue(square1.isSlippery());
		assertTrue(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
		assertFalse(square1.getSlipperyMaterial());
	}
	@Test 
	public void testSlipperyMaterial(){
		assertFalse(square1.isIceSlippery());
		assertFalse(square1.isWaterSlippery());
	}
	
	@Test 
	public void testCanHaveAsBorders_doubles(){
		Map<Direction, Border> newBorders = new HashMap<Direction, Border>();
		Door door1 = new Door(false);
		newBorders.put(Direction.WEST, door1);
		newBorders.put(Direction.EAST, door1);
		assertFalse(square1.canHaveAsBorders(newBorders));
		assertFalse(square2.canHaveAsBorders(newBorders));
		newBorders = new HashMap<Direction, Border>();
		door1.terminate();
		newBorders.put(Direction.NORTH, door1);
		assertFalse(square1.canHaveAsBorders(newBorders));
		newBorders = new HashMap<Direction, Border>();
		newBorders.put(Direction.WEST, square1.getBorderAt(Direction.FLOOR));
		assertFalse(square1.canHaveAsBorders(newBorders));
	}
	
	//Bewoonbaarheid (defensief):
	
	@Test 
	public void testInhabitability(){
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(BigInteger.valueOf(000),2)) == 0);
	}
	@Test 
	public void testInhabitabilityChanged() throws IllegalArgumentException, IllegalStateException{
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(7600),2));
		square1.alterTemperature(new Temperature(new BigDecimal(BigInteger.valueOf(500),1), TemperatureUnit.CELSIUS));
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(BigInteger.valueOf(-2),1)) == 0);
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(2000),2));
		square1.alterTemperature(new Temperature(new BigDecimal(BigInteger.valueOf(-150),1), TemperatureUnit.CELSIUS));
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(BigInteger.valueOf(-10),1)) == 0);
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(10000),2));
		square1.setLimitsTemperature(square1.getLowerLimitTemperature(), new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.alterTemperature(new Temperature(new BigDecimal(Integer.MAX_VALUE), TemperatureUnit.CELSIUS));
		assertTrue(square1.getInhabitability().compareTo(new BigDecimal(-1713002111395.282226562500)) == 0);
	}
	@Test (expected=ArithmeticException.class)
	public void testInhabitabilityOutOfUpperBound() throws Exception{
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(1000),2));
		square1.setLimitsTemperature(square1.getLowerLimitTemperature(), 
				new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.alterTemperature(new Temperature(new BigDecimal(Long.MAX_VALUE), TemperatureUnit.CELSIUS));
		square1.getInhabitability();
	}
	@Test (expected=IllegalArgumentException.class)
	public void testInhabitabilityOutOfLowerBound() throws Exception{
		square1.alterHumidity(new BigDecimal(BigInteger.valueOf(1000),2));
		square1.setLimitsTemperature(new Temperature(new BigDecimal(Long.MIN_VALUE), TemperatureUnit.CELSIUS),
				square1.getUpperLimitTemperature());
		square1.alterTemperature(new Temperature(new BigDecimal(Long.MIN_VALUE), TemperatureUnit.CELSIUS));
		square1.getInhabitability();
	}
	@Test
	public void testInhabitabilityHumidityOutOfBound() throws Exception{
		BigDecimal newHumidity = new BigDecimal(BigInteger.valueOf(100000),2);
		assertFalse(Square.isValidHumidity(newHumidity));
	}
	
	//accessibility
		
	private void canAccess(Square from, Set<Set<Square>> to) {
		for(Set<Square> set : to)
			for(Square square : set)
				assertTrue(from.canAccess(square));
	}
	
	private void cannotAccess(Square from, Set<Set<Square>> to) {
		for(Set<Square> set : to)
			for(Square square : set)
				assertFalse(from.canAccess(square));
	}
	
	@Test
	public void testAccessibilityInSameRoom() {
		Set<Set<Square>> accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(room5);
		canAccess(level2.getSquareAt(new Position(0, 0, 0)), accessibleRooms);
	}
	
	@Test
	public void testAccessibilityInDifferentRoomsWithDirectTeleportation() {
		Set<Set<Square>> accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(room6);
		accessibleRooms.add(room7);
		canAccess(level3.getSquareAt(new Position(0, 1, 0)), accessibleRooms);
		accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(room2);
		canAccess(level1.getSquareAt(new Position(0, 1, 0)), accessibleRooms);
	}
	
	@Test
	public void testAccessibilityInDifferentRoomsWithInDirectTeleportation() {
		Set<Set<Square>> accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(room3);
		accessibleRooms.add(room4);
		accessibleRooms.add(room5);
		canAccess(shaft3.getSquareAt(new Position(0, 0, 0)), accessibleRooms);
	}
	
	@Test
	public void testAccessibilityInDifferentDungeonsWithDirectTeleportation() {
		Set<Set<Square>> accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(room8);
		canAccess(shaft1.getSquareAt(new Position(0, 0, 0)), accessibleRooms);
	}
	
	@Test
	public void testAccessibilityInDifferentDungeonsWithInDirectTeleportation() {
		Set<Set<Square>> accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(room6);
		accessibleRooms.add(room7);
		accessibleRooms.add(room8);
		canAccess(shaft1.getSquareAt(new Position(0, 0, 0)), accessibleRooms);
	}
	
	@Test
	public void testAccessibilityToAllRooms() {
		Set<Set<Square>> accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(dungeon1rooms);
		accessibleRooms.add(dungeon2rooms);
		accessibleRooms.add(room8);
		canAccess(shaft3.getSquareAt(new Position(0, 0, 0)), accessibleRooms);
	}
	
	@Test
	public void testNoAccessibilityInDifferentRoomsWithNoTeleportation() {
		Set<Set<Square>> nonAccessibleRooms = new HashSet<Set<Square>>();
		nonAccessibleRooms.add(room2);
		cannotAccess(level2.getSquareAt(new Position(0, 0, 0)), nonAccessibleRooms);
	}
	
	@Test
	public void testNoAccessibilityInDifferentRoomsWithDirectReversedTeleportation() {
		Set<Set<Square>> nonAccessibleRooms = new HashSet<Set<Square>>();
		nonAccessibleRooms.add(room1);
		cannotAccess(shaft2.getSquareAt(new Position(0, 0, 0)), nonAccessibleRooms);
	}
	
	@Test
	public void testNoAccessibilityInDifferentRoomsWithInDirectReversedTeleportation() {
		Set<Set<Square>> nonAccessibleRooms = new HashSet<Set<Square>>();
		nonAccessibleRooms.add(room1);
		nonAccessibleRooms.add(room4);
		cannotAccess(shaft1.getSquareAt(new Position(0, 0, 0)), nonAccessibleRooms);
	}
	
	@Test
	public void testNoAccessibilityInDifferentDungeonsWithNoTeleportation() {
		Set<Set<Square>> nonAccessibleRooms = new HashSet<Set<Square>>();
		nonAccessibleRooms.add(room8);
		cannotAccess(level2.getSquareAt(new Position(0, 0, 0)), nonAccessibleRooms);
	}
	
	@Test
	public void testNoAccessibilityInDifferentDungeonsWithDirectReversedTeleportation() {
		Set<Set<Square>> nonAccessibleRooms = new HashSet<Set<Square>>();
		nonAccessibleRooms.add(room8);
		cannotAccess(level3.getSquareAt(new Position(0, 1, 0)), nonAccessibleRooms);
	}
	
	@Test
	public void testNoAccessibilityInDifferentDungeonsWithInDirectReversedTeleportation() {
		Set<Set<Square>> nonAccessibleRooms = new HashSet<Set<Square>>();
		nonAccessibleRooms.add(dungeon1rooms);
		nonAccessibleRooms.add(room8);
		cannotAccess(level3.getSquareAt(new Position(25, 25, 0)), nonAccessibleRooms);
	}
	
	@Test
	public void testNoAccessibilityWithTerminatedSquare() {
		Set<Set<Square>> accessibleRooms = new HashSet<Set<Square>>();
		accessibleRooms.add(room1);
		Square square = new NormalSquare();
		level1.addSquareAt(square, new Position(6, 1, 0));
		canAccess(square, accessibleRooms);
		Set<Set<Square>> nonAccessibleRooms = new HashSet<Set<Square>>();
		square.terminate();
		nonAccessibleRooms.add(dungeon1rooms);
		nonAccessibleRooms.add(dungeon2rooms);
		nonAccessibleRooms.add(room8);
		cannotAccess(square, nonAccessibleRooms);
	}
}
